﻿/*# A component of the Realistic Book software# from the New Zealand Digital Library Project at the # University of Waikato, New Zealand.## Copyright (C) 2007 New Zealand Digital Library Project## This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the# GNU General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//*****************************************************************Realistic Book application	Converting an XHTML or PDF document to a 2D book with page	turning ability.by Veronica Liesaputra --- 1 August 2007******************************************************************//*=================Global variables=================*//* Variables used just to help recursion */var img_counter = 0;//stored the image number counter of a sectionvar start_style="";//the starting tagvar end_style="";//the ending tagvar test_content;//the text field of the pagevar annoBookmarkList = new Array();//list of annotation and bookmarkvar text_height = 0;//current height of text inside the paragraphvar orphan_height = 0;//current height of the possible orphan in the paragraphvar currParagraph = new Array();//the list of lines in the current paragraphvar isLink = false;//whether we are dealing with the links with mouseovervar text_align="left";//the text alignmentvar wikiWord = '';//the words inside the wikiid hrefvar wikiID = '';//the id inside the wikiid hrefvar isImg = 0;var line_height = 0;var start_inline="";//the starting inline tagvar end_inline="";//the ending inline tag/* Variables for the reading tools */var allowNote = true;//allow annotatingvar allowBookmark = true;//allow bookmarkingvar allowSave = true;//allow savingvar allowPrint = true;//allow printingvar allowOption = true;//allow changing optionvar allowAnimate = true;//display animating arrowvar allowSearch = true;//allow text searchingvar allowFlipping = true;//allow keep flippingvar allowThumbnail = true;//display thumbnail listvar allowZoom = true;//allow changing zoom factorvar allowNavigation = true;//display navigation tools/* Variables for the page layout */var stageW = 450;//width of the open bookvar stageH = 600;//height of the open bookvar top_margin = 25;//the top margin from the text blockvar bottom_margin = 25;//the bottom margin of the text blockvar left_margin = 25;//the left margin of the text blockvar right_margin = 25;//the right margin of the text blockvar orphanLine = 2;//number of orphaned linesvar widowLine = 2;//number of widowed linesvar addRunningHeader = true;//whether the page has running headervar addPageNumber = true;//whether the page has a page numbervar start_numbering = -1;//the starting page number not using the roman numeralvar yAdd = 10;//the additional leeway for the text_content heightvar headerSize = 10;//the running headervar numberSize = 10;//the page number/* Variables for the selected item in the book */var sel_fmt;//the selected text formatvar sel_element;//the name of the selected element of the bookvar sel_all = true;//whether the format should be apply to allvar sel_section;//the selected section objectvar sel_bookmark;//the selected bookmark objectvar sel_text;//the selected textvar sel_id/* Variables for the book display */var start_open_page;//the number where the book should be opened//page edgesvar off_x;//x offset used to draw the page framevar off_y;//y offset used to draw the page framevar frameBitmap = new Array();//hold small bitmap for creating the page frame//book covervar cover_margin;//the margin from the hardcover to the pagevar book_margin;//the margin from the cover to the pagevar is_soft_cover;//whether the book is paperbackvar cover_bkcolour;//background colour for the cover//pagevar is_flexible;//whether the page is stiff or flexiblevar page_bkcolour;//background colour for the pagevar	shadow_alpha;//the shadow's level//bookmarkvar bookmark_base;//the base bookmark colourvar bookmark_cutoff = 22;//the number of bookmark in a sequencevar bookmark_height;//the height of the bookmarkvar bookmark_max_level;//the bookmark maximum section's levelvar bookmark_use_colour;//whether bookmark coloured based on section's levelvar	bookmark_use_width;//whether bookmark's width is based on section's level var	bookmark_use_section;//whether the page is bookmarked based on section var bookmark_show_pic;//whether we should show bookmark for pictures var bookmark_show_user;//whether we should show bookmark added by uservar bookmark_show_note;//whether we should show bookmark for annotationsvar myTransform;//the cover colour transformvar myTransform2;//the page colour transform//list of colour would be use for the bookmark based on section's level //followed by pictures, and searchvar bookmark_colour_section = new Array();//page turningvar	xStep; var yStep;//the actual step use in the step turnvar	xStepL; var yStepL;//the step use when p is on the left sectionvar	xStepR; var yStepR;//the step use when p is on the right sectionvar last_top;//stored the last complete page turn start position (top or bottom)var target_page = -1;//the page user wants to jump tovar turnInterval;//the interval id for the automatic page turningvar num_page_turn;//the number of turns before it jumped to the pagevar PAGE_STEP;//the waiting period & the number of frame before reaching cornervar isLoop = false;//whether the book should be keep loopingvar jumpWait = 700;//the waiting period before turning the pagevar frontPause = -1;//the waiting period on the first pagevar backPause = -1;//the waiting period before going to the first pagevar jumpInterval;//the interval id for waiting to jump to the first page//zoomvar zoom_style;//the current zoom stylevar stage_zoom;//the current zooming factor/* Variables for performing the page turning */var pax; var pay; var pbx; var pby;//top, bottom coordinate of the left pagevar pcx; var pcy; var pdx; var pdy;//top, bottom coordinate in the center bookvar pex; var pey; var pfx; var pfy;//top, bottom coordinate of the right pagevar p3_rx = 0;	var p3_ry = 0;//x and y position of point R for p2 with bookmarkvar	moveLeft;//whether p is moving to the left or rightvar	moveTop;//whether p is moving to the top or bottomvar start_x;	var start_y;//the point where the mouse is pressedvar orig_x;		var orig_y;//the corner the p representvar offset;//offset to allow a region instead of a precise point to be pressed//whether it is a single mouse click (0 = no click, 1 = single click)var isSingle = 0;var oldMouseX = 0; var oldMouseY = 0;//last xy mouse press positionvar prevMouseX = 0; var prevMouseY = 0;//last xy mouse move positionvar	PageNum;//total number of pages in the book var CurPageNum;//the current page number of the left pagevar lastVisited;//the last page number visited before user jump/* Variables used for search */var searchTerm="";//the search stringvar matchCase=false;//whether the search is case sensitivevar inclNote=true;//whether we need to search the comments as wellvar inclSynonyms=true;//whether we should search for hyperlinks with same hrefvar wikiList = new Array();//synonyms list (term, wiki_term)var wikiDef = new Array();//hash map (wiki_id, wiki_text)var indexList = new Array();//hash map (term, occurrence)/* Variables used for tools in the toolbar */var combo_open = false;//whether the combo box is openedvar is_pen = -1;//whether the pointer is a penvar drag_movie = false;//whether the book is being dragged around/* Variables used for the right-click menu */var newMenu = new ContextMenu();//the main right click menuvar main_menu;//the more book options menuvar main_menu_open = false;//whether the more book options menu is opened/* Variables for the list of element in the book */var page_link = new Array();//hash map (link_id, link_obj)var bookmarks = new Array();//hash map (bookmark_id, bookmark_obj)var page_bookmark = new Array();//lst of pages that have bookmarks in the bookvar pages = new Array();//stored the list of pagesvar books = new Array();//list of sections in the book var annos = new Array();//hash map (anno_id, anno_obj)var annos_length = 0;//the latest valid anno_idvar headerStyle = new Array();//hash map (section_level, [start_style, end_style])/* Variables for the list filenames of the book component */var styleFile;//the url for the stylesheetvar styleCSS;//the loaded css for all text contentvar src_image; //the url for cover imagevar doc_url;//the url of the XML book structure filevar anno_url;//the url of the XML book annotation filevar source_filename;//the name of the source PDF filevar loadedClip;//the list of cached pagesvar page_folder;//the name of the folder holding all the swf filesvar oldFocus = "";//the previous text being on focus that is annotationvar isGreenstone=true;//whether this is a Greenstone XHTML format/*=================Functions=================*//*----------- Create book structure ------------*//** * Set the default book parameters value */function initBookParameters() {	off_x = 0.5; off_y = 0.1; //offset used to draw the page frame	cover_margin = 10;//the margin from the cover to the page	book_margin = cover_margin;	shadow_alpha = 60;//the shadow max value	is_soft_cover = false;//the cover type	is_flexible = true;//the page type	page_alpha = 100;//transparency for the pages	bookmark_max_level = Infinity;//the bookmarking maximum level	//the style of the bookmark	bookmark_use_colour = true; 	bookmark_use_width = true; 	bookmark_use_section = true; 	bookmark_show_pic = false; 	bookmark_show_user = true;	//the waiting period also the number of frame before reaching corner	PAGE_STEP = 5;	num_page_turn = 4;//the number of turn before it skip to the page	zoom_style = "fit stage";//the initial zoom style	_root.toolbar.setHideToolbar("false");}/** * Parse aXML tree and generate the annotation and bookmark list for the book * Parameters: * aXML the xml tree for the annoation and bookmark */function parseAnnoXML(aXML) {	_root.saveAction("root","parsing Annotation XML");		parseTree(aXML,null);		setBookmarkAnnotation(); 		finalizeParse();		aXML.removeNode();}/** * Parse myXML tree and create a book * Parameters: * myXML the xml tree for the book */function parseXML(myXML) {	_root.saveAction("root","parsing XML");		//setting the size of the book	if ((stageW == null)||(stageW == -1))		stageW = 450;			if ((stageH == null)||(stageH == -1))		stageH = 600;		initBookParameters();		setBookSize(stageW,stageH);		//create the inital section of the book	var book_section = new BookSection("","",0);		//create the first page of the book	var book_page = new BookPage(pages.length,"<added />",book_section);	book_page.section_page = book_page;	books.push(book_section);	pages.push(book_page);	//parse through the xml	line_height = 0;	test_content.htmlText="W";	line_height = test_content.textHeight;//get the height of a character	parseTree(myXML,book_section);	writeParagraphToPage(); 		//we need to make distinction between Greenstone format and not for HTML	if ((source_filename == null) && (page_folder == null)) {		//create all the pages before the first actual content of the book		var pages2 = new Array();			//blank page		var blank = new BookPage(pages2.length,"<added />",book_section);		pages2.push(blank);				//blank page		var blank2 = new BookPage(pages2.length,"<added />",book_section);		pages2.push(blank2);				if (_root.strIsEmpty(src_image) == false) {			//book cover			var cover_img = "<toc><img src ='" + src_image + "' width ='" + 							test_content._width + "' height ='" + 							test_content._height + "' hspace ='" + 10 + 							"' vspace ='" + 10 + "' align ='right' />" + 							"<P></P></toc>";			var book_cover1 = new BookPage(pages2.length,cover_img,book_section);			book_cover1.page_bookmarktext = "Front Cover";			pages2.push(book_cover1);						//blank page			var blank3 = new BookPage(pages2.length,"<added />",book_section);			pages2.push(blank3);		}				var xp = 0;		var toc_num;		var toc;		var leftOver = 0;		var toc_txt = "<toc><wrap /><p align='center'><font size='18'>" + 					  "<b>Table of Contents</b></font></p><br/><br/>";		test_content.htmlText = toc_txt;		var toc_ptxt = test_content.text;		if (book_section.subsection[0].subsection[0] != null) {			//sectionalized document			if (isGreenstone == true) {				//the title page				pages.shift();				while (pages[0].page_section[0].section_tnum == "")				{					var title_page = pages.shift();					title_page.page_section = [book_section];					pages2.push(title_page);				}							xp = pages2.length;				if ((xp%2) == 1)				{					//blank page					var blank4 = new BookPage(pages2.length,"<added />",											  book_section);					pages2.push(blank4);				}							//table of content				toc = new BookPage(pages2.length,toc_txt,books[0].subsection[0]);			} else {				toc_txt = "<soc></soc>" + toc_txt;				toc = new BookPage(pages2.length,toc_txt,books[0].subsection[0]);				leftOver = books[0].subsection[0].subsection[0].section_page.page_num - 						   books[0].subsection[0].section_page.page_num - 1;			}			toc.plain_text = toc_ptxt;						var toc_num = pages2.length;			books[0].subsection[0].section_page = toc;//put the bookmark			toc.page_bookmarktext = "Table of Contents";			pages2.push(toc);			createTableOfContent(book_section,pages2);			pages2[pages2.length-1].page_text += "</toc>";			updateHTMLIndex (pages2[pages2.length - 1]);						//add additional pages to make it end on the left side			xp = pages2.length;			if (((xp+leftOver)%2) == 1)			{				//blank page				var blank5 = new BookPage(pages2.length,"<added />",										  getLastSection(pages2[pages2.length-1]));				pages2.push(blank5);			}		}				//add the front section with the actual content of the book		pages = pages2.concat(pages);				//fix all the page numbering		fixPageNumber();				//add additional pages to make it end on the left side		if (((pages.length - 1)%2) == 0)		{			var b_page = pages[pages.length - 1];			var new_page = new BookPage(b_page.page_num + 1,"<added />",										getLastSection(b_page));			pages.push(new_page);		}			if (_root.strIsEmpty(src_image) == false)		{			var bt_page = pages[pages.length - 1];			//back cover			var blank6 = new BookPage(bt_page.page_num + 1,"<added />",									  getLastSection(bt_page));			pages.push(blank6);			//blank page			var blank7 = new BookPage(bt_page.page_num + 2,"<added />",									  getLastSection(blank6));			pages.push(blank7);		}				//blank page		var bl_page = pages[pages.length - 1];		var blank8 = new BookPage(bl_page.page_num + 1,"<added />",								  getLastSection(bl_page));		pages.push(blank8);				if (start_numbering == -1)//numbering			start_numbering = 4;					if (book_section.subsection[0].subsection[0] != null){			//sectionalized document			//need to recreate table of content to make sure all link is right			var arrayA = pages.slice(0,toc_num + 1); //get all pages before TOC			arrayA[toc_num].page_text = toc_txt;			updateHTMLIndex (arrayA[toc_num]);			arrayA[toc_num].plain_text = toc_ptxt;			var arrayB = pages.slice(xp,pages.length);//get all pages after TOC			createTableOfContent(book_section,arrayA);			arrayA[arrayA.length-1].page_text += "</toc>";			updateHTMLIndex (arrayA[arrayA.length - 1]);			pages = arrayA.concat(arrayB);//combine them back together		}	}	else {		//create all the pages before the first actual content of the book		var pages2 = new Array();			//blank page		var blank = new BookPage(pages2.length,"<added />",book_section);		pages2.push(blank);				//add the front section with the actual content of the book		pages = pages2.concat(pages);				//fix all the page numbering		fixPageNumber();				var bt_page = pages[pages.length - 1];		//blank page		var blank7 = new BookPage(bt_page.page_num + 1,"<added />",								  getLastSection(bt_page));		pages.push(blank7);				//add blank pages if pages.length is not even		if ((pages.length % 2) == 0) {			//blank page			var blank8 = new BookPage(bt_page.page_num + 2,"<added />",									  getLastSection(bt_page));			pages.push(blank8);		}				if (start_numbering == -1)//numbering			start_numbering = 2;	}		if ((pages.length % 2) == 0)		return errorStatusXML(-11);//total number of page is not even	if(anno_url != null)		loadAnnoXMLforURL(anno_url);	else		finalizeParse();		//clear the XML tree and the test content box	myXML.removeNode();	test_content.htmlText="";}/** * Finalize the book scene according to the book and annotation files */function finalizeParse() {	if (_root.toolbar.fastForward.over.arrowbtn2._alpha == 0)		_root.toolbar._visible = true;			//display the book 	initPageTurningScene();	if ((strIsEmpty(start_open_page) == false) && 		(isNaN(start_open_page) == false)) {		var n = Number(start_open_page);		if ((n % 2) == 0)			n = n - 1;		target_page = n;				CurPageNum = Number(target_page);		endpageturnsetup();	} else { start_open_page = null; }		//make the stage appear and the progress bar disappear	_root.stage._visible = true;	_root.splash.my_pb.label = "";	_root.splash._visible = false;	_root.stage.cover._visible = false;}/** * Get the latest section in the page * Parameters * bPage the page */function getLastSection(bPage) {	if (bPage.page_section.length != bPage.page_section_length) {		bPage.page_section_length = bPage.page_section.length;		bPage.page_last_section = bPage.page_section[bPage.page_section_length - 1];	}	return bPage.page_last_section;}/** * Set the y position of the bookmark so that it doesn't overlap * with the section, picture or note bookmark * Parameters * num		the page number * curry	the supposed y position * Return * The supposed y position */function setBookmarkY (num, curry) {	var accy = curry;		var bType = ["S", "P", "N", "U"];	var off = 0;	while (off >= -1) { 		for (var i = 0; i < bType.length; i++) {			var bk = _root.pages[num + off][("page_bookmark" + bType[i])];			if (bk != null) {				var bk_y = bk.bookmark_y;				if (accy == bk_y) {					accy = (accy + 1) % bookmark_cutoff;				}			}		}		off--;		if ((num % 2) == 0) {			off--;		}	}	return accy;}/** * Set the annotation or bookmark list of the pages in the book */function setBookmarkAnnotation() {	var b_numN = 0;//bookmark_number based on note	var b_numU = 4;//bookmark_number based on user		for (var i = 0; i < _root.pages.length; i++) {		var pnum = _root.pages[i].page_num;		if (annoBookmarkList[pnum] != null) {			_root.pages[i].page_bookmarkU = annoBookmarkList[pnum].blist;			if (_root.page_bookmark[i] == null)				_root.page_bookmark[i] = i;			if (annoBookmarkList[pnum].blist != null) {				_root.pages[i].page_bookmarkU.bookmark_page = _root.pages[i];				var by = setBookmarkY(i, b_numU % bookmark_cutoff);				_root.pages[i].page_bookmarkU.bookmark_y = by;				b_numU = by++;			}			_root.pages[i].page_annotation = annoBookmarkList[pnum].alist;			if ((annoBookmarkList[pnum].alist != null) &&				(annoBookmarkList[pnum].alist.length > 0)) {				for (var k = 0 ; k < _root.pages[i].page_annotation.length; k++) {					_root.pages[i].page_annotation[k].annotation_page = _root.pages[i];				}				b_numN = createAnnoBookmarkFor(i, b_numN);			}						annoBookmarkList[pnum].blist = null;			annoBookmarkList[pnum].alist = null;			annoBookmarkList[pnum] = null;		}	}		annoBookmarkList = null;	delete annoBookmarkList;}/** * Iterate through the XML node, get the annotation or bookmark list for a page, * and place it in the appropriate array * Parameters: * node current XML node we want to parse * num  the page number */function parseBookmarkAnnotation(node,num) {	if (annoBookmarkList[num] == null) {		annoBookmarkList[num] = {alist:[], blist:null};	}		for (var i = 0 ; i < node.childNodes.length; i++) {		var currNode = node.childNodes[i];		var currName = (currNode.nodeName).toLowerCase();				var p_y = 0; 		var p_x = 0;		var p_width = 10;		var p_page = null;		var p_color = 0x000000;		var p_text = "";		if (currName == "bookmark") {			var p_id = "";			var p_visible = true;						var attr = currNode.attributes;			for (var attr_name in attr) {				var a_nmm = attr_name.toLowerCase();				var a_val = attr[attr_name];				if (a_nm == "id") {					p_id = a_val;				} else if (a_nm == "visible") {					p_visible = stringToBoolean(a_val);				} else if (a_nm == "text") {					p_text = a_val;				} else if (a_nm == "colour") {					p_color = Number(a_val);				}			}						var new_bk = new _root.BookBookmark(0,0,getBookmarkWidthFor("U", num),												null,p_text,p_color);			new_bk.bookmark_visible = p_visible;			new_bk.bookmark_name = p_id;			annoBookmarkList[num].blist.push(new_bk);		} else if (currName == "annotation") {			var p_height = 10;			var p_alpha = 100;			var p_resize = false;			var p_id = annos_length;			var p_max = true;			var p_child = null;						var attr = currNode.attributes;			for (var attr_name in attr) {				var a_nm = attr_name.toLowerCase();				var a_val = Number(attr[attr_name]);				if (a_nm == "x") {					p_x = a_val;				} else if (a_nm == "y") {					p_y = a_val;				} else if (a_nm == "width") {					p_width = a_val;				} else if (a_nm == "colour") {					p_color = a_val;				} else if (a_nm == "height") {					p_height = a_val;				} else if (a_nm == "transparency") {					p_alpha = a_val;				} else if (a_nm == "isresized") {					if (attr[attr_name].toLowerCase() == "true") {						p_resize = true;					}				} else if (a_nm == "maximize") {					if (attr[attr_name].toLowerCase() == "false") {						p_max = false;					}				} else if (a_nm == "id") {					p_id = a_val;					annos_length = Math.max(annos_length,a_val);				} else if (a_nm == "child_id") {					p_child = "" + a_val;					annos_length = Math.max(annos_length,a_val);				}			}						var new_anno = new _root.BookAnnotation(p_x, p_y, null,"");			new_anno.annotate_id = "" + p_id;			annos_length++;			if (annos[new_anno.annotate_id] == null)				annos[new_anno.annotate_id] = new Object();			annos[new_anno.annotate_id].obj = new_anno;			annoBookmarkList[num].alist.push(new_anno);						new_anno.annotate_width = p_width;			new_anno.annotate_height = p_height;			new_anno.annotate_colour = p_color;			new_anno.annotate_transparency = p_alpha;			new_anno.isResized = p_resize;			new_anno.annotate_maximize = p_max;			new_anno.annotate_child = p_child;			if (p_child != null) {				if (annos[p_child] == null)					annos[p_child] = new Object();				annos[p_child].parent = new_anno.annotate_id;			}						for (var k = 0; k < currNode.childNodes.length; k++) {				var nextNode = currNode.childNodes[k];				var nextName = (nextNode.nodeName).toLowerCase();								if (nextName == "text") {					new_anno.annotate_text = "";					for (var w = 0; w < nextNode.childNodes.length; w++) {						new_anno.annotate_text += nextNode.childNodes[w].toString();					}				} else if (nextName == "highlighted") {					new_anno.annotate_selText = "";					for (var w = 0; w < nextNode.childNodes.length; w++) {						new_anno.annotate_selText += nextNode.childNodes[w].toString();					}				} else if (nextName == "line") {					var new_line = new Line();					new_anno.annotate_line.push(new_line);										var attr = nextNode.attributes;					for (var attr_name in attr) {						var a_nm = attr_name.toLowerCase(); 						if (a_nm == "orig") {							new_line.orig = _root.pointTxt(attr[attr_name]);						} else if (a_nm == "pointlist") {							var sArr = attr[attr_name].split(";");							for (var w = 0; w < sArr.length; w++) {								new_line.pointlist.push(_root.pointTxt(sArr[w]));							}						} else if (a_nm == "fname") {							new_line.fName = _root.unescapeQuotes(attr[attr_name]);						} else if (a_nm == "minpt") {							new_line.minPt = _root.pointTxt(attr[attr_name]);						} else if (a_nm == "maxpt") {							new_line.maxPt = _root.pointTxt(attr[attr_name]);						} else if (a_nm == "alpha") {							new_line.alpha = Number(attr[attr_name]);						} else if (a_nm == "thickness") {							new_line.thickness = Number(attr[attr_name]);						} else if (a_nm == "colour") {							new_line.colour = Number(attr[attr_name]);						} else if (a_nm == "fill") {							if (attr[attr_name] == "true")								new_line.fill = true;						}					}				}			}		}	}}/** * Recursively goes down the XML and HTML nodes, and build the book. * Parameters: * node	current XML/HTML node we want to parse * section	the current book section we are building */function parseTree(node, section) {	for (var i = 0; i < node.childNodes.length; i++) {		var currNode = node.childNodes[i];//current child node		var currName = (currNode.nodeName).toLowerCase();//the tag name		test_content.htmlText = "";//reset the content of the test page				if ((_root.strIsEmpty(currName) == false) && 			((currName == "metadata") || (currName == "bookmarklist") || 			 (currName == "annotationlist") || (currName == "newpage") || 			 (currName == "section") || (currName == "description") ||			 ((currName.charAt(0) == "h") && 			  (isNaN(currName.charAt(1)) == false)))) {			section = parseTreeXMLNode(currNode, section);		} else {			section = parseTreeHTMLNode(currNode,section);		}	}	return section;}/** * Return the value for the specified attribute name. If the specified attribute * does not exists, return the current value of the specified variable. * Parameters: * map	the hash map for attribute name and its value * attr_name the specified attribute name * curr_var	 the current value of the attribute */function getAttrValue (map, attr_name, curr_var) {	if (map[attr_name] != null) {		return map[attr_name];	}	return curr_var;}/** * Given the current node, return associative array of the recognized attribute * and its value * Parameters * currNode the current node * Return * hash map (attrName, attrValue) */function getAttrMapFor (currNode) {	var attr = currNode.attributes;	var map = new Object();	var map_text = "";	for (var attr_name in attr) {		var vn = attr[attr_name];		var an = attr_name.toLowerCase();//the attribute name		var ev;//the extracted attribute value		if (_root.strIsEmpty(vn) == false) {			ev = vn;			if (an == "filename") {//for section and newpage tag				ev = removeEmptyStrings((_root.unescapeQuotes(vn)).split(";"));			} else if (an == "pagebreak") {//for section tag				ev = stringToBoolean(vn);			} else if (an == "addtitle") {//whether to add section title to text				ev = stringToBoolean(vn);			} else if ((an == "bold") || (an == "italic")) {//for section tag				ev = stringToBoolean(vn);			} else if (an == "src") {//for image tag				ev = vn;			} else if ((an == "width") || (an == "height")) {//for image tag				ev = Math.abs(Number(vn));			} else if (an == "align") {//for paragraph tag				vn = replaceString (vn.toLowerCase(), "justify", "left");				vn = replaceString (vn.toLowerCase(), "centre", "center");				ev = vn;			} else if (an == "href") {//it's an hyperlink				if (vn.charAt(0) == '#') {//an internal link					var link_name = vn.substring(1, vn.length());					vn = "asfunction:_root.gotoLink," + link_name;				}				ev = vn;			} else if ((an == "name") || (an == "title")) {//for link tag				ev = vn;			} else if ((an == "synonym") || (an == "active")) {				ev = stringToBoolean(vn);			} else if (an == "leading") {				ev = Number(vn);			} else if (an == "size") {//the size of the font				vn = replaceString (vn.toLowerCase(), "pt", "");//remove point				vn = replaceString (vn, "px", "");//remove pixels				vn = replaceString (vn, " ", "");//remove the space				var isAdd = 0;				//we need to change the relative font size to fixed one				if (vn.indexOf("+") == 0) {					vn = replaceString(vn, "+", "");					isAdd = 1;				} else if (vn.indexOf("-") == 0) {					vn = replaceString(vn, "-", "");					isAdd = -1;				}				var font_size = Number(vn);				if (isNaN(font_size) == true) {					font_size = 0;				} else if (isAdd != 0) {					var fSize = 12;					//the current line of the book					var currLine = currParagraph[currParagraph.length - 1];					if (currLine != null)						fSize = currLine.fontSize;					font_size = fSize + (isAdd * font_size); 				}				font_size = Math.min(Math.max(1, font_size), 									 test_content._width - 30);				ev = "" + font_size; 			} else if ((an == "face") || (an == "font")) {//the name of the font				var f_arr = removeEmptyStrings((vn.toLowerCase()).split(";"));				var f_val = "";				for (var fi = 0; fi < f_arr.length; fi++) {					var fFace = trim(f_arr[fi]);					if ((fFace.indexOf("arial") != -1) || 						(fFace.indexOf("courier new") != -1) || 						(fFace.indexOf("georgia") != -1) || 						(fFace.indexOf("times new roman") != -1) || 						(fFace.indexOf("verdana") != -1)) {						if (f_val != "") 							f_val += "; ";						f_val += fFace;					}				}				if (_root.strIsEmpty(f_val) == true) {					f_val = "arial";				}				ev = f_val;			} else if ((an == "leftmargin") || (an == "rightmargin") ||					   (an == "blockindent") || (an == "indent") ||					   (an == "tabstops") || (an == "span")) {				//for attribute to be ignored				ev = null;			}						//add to the map			if (ev != null) {				map[an] = ev;				map_text += " " + an + "='" + ev + "'";			}		}	}	map["map_text"] = map_text;	return map;}/** * Add a new line to the current paragraph * Return: * the new line */function addALineToCurrParagraph() {	//the current line of the book	var currLine = currParagraph[currParagraph.length - 1];		var newLine = new BookLine();	if (currLine != null) {		newLine.fontSize = currLine.fontSize;		newLine.lineLeading = currLine.lineLeading;	}	newLine.lineStartStyle = start_style;	newLine.lineEndStyle = end_style;	newLine.lineAlign = text_align;	if ((currLine != null) && (isLink == true)) {		//this text belongs to a hyperlink with mouse over		var lastLink = currLine.lineLinks[currLine.lineLinks.length - 1];		var newLink = new BookLink();		newLink.linkText = lastLink.linkText;		newLink.linkURL = lastLink.linkURL;		newLine.lineLinks.push(newLink);	}	currParagraph.push(newLine);	currLine = newLine;		return currLine;}/** * Create a new paragraph with a resetted tag * Return * The starting line from that paragraph */function completeCurrParagraph () {	//we need to write all the lines before this tag	writeParagraphToPage();		if (currParagraph.length == 0)		return addALineToCurrParagraph();	else		return currParagraph[currParagraph.length - 1];}/** * Set the global header style for the specified level * Parameters: * lvl  the header level we want to set */function initHeaderStyle (lvl) {	var font_size = 12;	var font_face = "Arial";	var sec_italic = false;	var sec_bold = true;	if (currLine != null) {		var tst = currLine.lineStartStyle + "h" + currLine.lineEndStyle;		test_content.htmlText = tst;		var my_fmt = test_content.getTextFormat(0, 1);		font_size = my_fmt.size;		font_face = my_fmt.font;		sec_italic = my_fmt.italic;		sec_bold = my_fmt.bold;	}		font_size += Math.max((4 - lvl) * 2, 0);	font_size = Math.min(Math.max(1, font_size), test_content._width - 30);		var sec_break = true;	var sec_align = "center";	if (lvl > 2) {		sec_align = "left";		sec_break = false;	}			headerStyle[lvl] = {align:sec_align, bold:sec_bold, face:font_face, 						italic:sec_italic, size:font_size, pagebreak:sec_break};}/** * Write the title of the current section to the page * Parameters: * section	the current section */ function writeSectionTitle (section) { 	var s_text = "<soc>";	if (section.section_addtitle == true) {		//add the section title to the top of the window browser			if ((isSetTitle == false) && (section.section_level == 1)) {			ExternalInterface.call("setDocumentTitle", s_title);			isSetTitle = true;		}		//add section title to the page		if (section.section_page.page_slidesname.length == 0) {			s_text += "<p align='" + section.section_align + "'>";			s_text += "<br />";			s_text += "<font size='" + section.section_fsize + 					  "' face='" + section.section_font + "'>";			if (section.section_bold == true)				s_text += "<b>";			if (section.section_italic == true)				s_text += "<i>";			if (strIsEmpty(section.section_tnum) == false)				s_text += section.section_tnum + " ";			s_text += section.section_title;			if (section.section_bold == true)				s_text += "</b>";			if (section.section_italic == true)				s_text += "</i>";			s_text += "</font><br /><br /></p>";		}	}	s_text += "</soc>";		//we need to ensure that <soc> and </soc> always in the same page	var b_page = pages[pages.length - 1];	test_content.htmlText = b_page.page_text + s_text;	if ((test_content.textHeight + yAdd) >= test_content._height) {		//go to new page		if ((b_page.page_slidesname.length == 0) && 			(_root.strIsEmpty(b_page.page_text) == false)) {			var pStr = "";			if (isEndTagABlock() == true) {				pStr += end_style.substring(end_inline.length);			} else {				pStr += end_style;			}			b_page.page_text += pStr;			updateHTMLIndex (b_page);			addNewline(b_page, end_style);			if (section.section_page.page_num == b_page.page_num) {				//we need to remove the section from the old page				b_page.page_section.pop();			}		}				isImg = 0;		var new_page = new BookPage(pages.length, "", section);		pages.push(new_page);		section.section_page = new_page;	}		var tempNode = new XML(s_text);	parseTreeHTMLNode(tempNode.childNodes[0], section);	var b_page = pages[pages.length - 1];	var secI = b_page.page_text.lastIndexOf("<soc>");	if (secI > 0) {		var initStr  = b_page.page_text.substring(0,secI);		var endI = b_page.page_text.lastIndexOf("</soc>") + 6;		var midI = b_page.page_text.substring(secI, endI);		var pStr = initStr;		if (isEndTagABlock() == true) {			pStr += end_style.substring(end_inline.length);		} else {			pStr += end_style;		}		pStr += midI + start_style;		b_page.page_text = pStr;		updateHTMLIndex (b_page);	} }/** * Get the new section number text if a new section is added to the * given section * Parameters: * secParent the given section */ function setSectionNumber (secParent) { 	var s_num = ""; 	if ((secParent != null) && (secParent.section_level >= 1)) { 		s_num += (secParent.subsection.length + 1); 		if (secParent.section_tnum != "") { 			return (secParent.section_tnum + "." + s_num); 		} 	} 	return ("" + s_num); }/** * Given the current description tag, set the global variables * Parameters: * currNode the description node * section	the current section */function parseDescriptionTag (currNode, section) {	for (var mI = 0; mI < currNode.childNodes.length; mI++) {		var metadataNode = currNode.childNodes[mI];		var attr = metadataNode.attributes;		for (var attrOrig_name in attr) {			var lCase = attrOrig_name.toLowerCase();			attr[lCase] = attr[attrOrig_name];		}		var an = attr["name"].toLowerCase();		var vn = metadataNode.childNodes[0].nodeValue;				if (an == "greenstone") {			isGreenstone = stringToBoolean(vn);		} else if (an == "allowrunningheader") {			addRunningHeader = stringToBoolean(vn);		} else if (an == "allowpagenumber") {			addPageNumber = stringToBoolean(vn);		} else if (an == "showbookmarkuser") {			bookmark_show_user = stringToBoolean(vn);		} else if (an == "keepflipping") {			isLoop = stringToBoolean(vn);			_root.toolbar.setPenButton();		} else if (an == "allowprint") { 			allowPrint = stringToBoolean(vn);		} else if (an == "allownote") {			allowNote = stringToBoolean(vn);		} else if (an == "allowbookmark") { 			allowBookmark = stringToBoolean(vn);		} else if (an == "allowsave") { 			allowSave = stringToBoolean(vn);		} else if (an == "allowoption"){ 			allowOption = stringToBoolean(vn);		} else if (an == "allowanimate") { 			allowAnimate = stringToBoolean(vn);		} else if (an == "allowsearch") { 			allowSearch = stringToBoolean(vn);		} else if (an == "allowflipping") { 			allowFlipping = stringToBoolean(vn);		} else if (an == "allowthumbnail") { 			allowThumbnail = stringToBoolean(vn);		} else if (an == "allowzoom") { 			allowZoom = stringToBoolean(vn);		} else if (an == "allownavigation") {			allowNavigation = stringToBoolean(vn);				}			if (_root.strIsEmpty(vn) == false) {			if (an == "title") {				//get the title name of the section				var s_title = convertHTMLEntities(vn);				section.section_title = s_title;				writeSectionTitle (section);			} else if (an == "filename") {				source_filename = vn;			} else if (an == "pagefolder") {				page_folder = vn;			} else if (an == "pagesize") {				var xs = vn.split("x");				var w = Math.abs(Number(trim(xs[0])));				var h = Math.abs(Number(trim(xs[1])));				if ((xs.length == 2) && (isNaN(w) == false) && 					(isNaN(h) == false)) {					stageW = w;					stageH = h;					setBookSize(stageW,stageH);				}			} else if (an == "topmargin") {				top_margin = Math.abs(Number(vn)); 			} else if (an == "bottommargin") { 				bottom_margin = Math.abs(Number(vn));			} else if (an == "leftmargin") {				left_margin = Math.abs(Number(vn));			} else if (an == "rightmargin") {				right_margin = Math.abs(Number(vn));			} else if (an == "startnumbering") {				start_numbering = Math.abs(Number(vn)) + 1;			} else if (an == "orphancount") { 				orphanLine = Math.abs(Number(vn));			} else if (an == "widowcount") {				widowLine = Math.abs(Number(vn));			} else if (an == "hidetoolbar") { 				_root.toolbar.setHideToolbar(vn.toLowerCase());			} else if (an == "zoomstyle") {				zoom_style = vn.toLowerCase();			} else if (an == "pagecolour") {				page_bkcolour = Number(vn); 			} else if (an == "covercolour") {				cover_bkcolour = Number(vn);			} else if (an == "bookmargin") {				cover_margin = Math.abs(Number(vn)); 			} else if (an == "xedgeoffset"){ 				off_x = Math.abs(Number(vn));			} else if (an == "yedgeoffset") {				off_y = Math.abs(Number(vn));			} else if (an == "openatpage") {				start_open_page = Math.abs(Number(vn));			} else if (an == "paperback") {				setCoverStyle(vn.toLowerCase());			} else if (an == "pagetype") {				setPageStyle(vn.toLowerCase());			} else if (an == "shadow") {				setShadowStyle(vn.toLowerCase());			} else if (an == "bookmarkbasecolour") { 				bookmark_base = Number(vn);			} else if (an == "tabstyle") {				setTabStyle(vn.toLowerCase());			} else if (an == "snapto") {				setSnapStyle(vn.toLowerCase());			} else if (an == "bookmarkcutoff") {				bookmark_cutoff = Math.abs(Number(vn));			} else if ((an == "waittofront") || (an == "backpause")) {				backPause = Math.abs(Number(vn));			} else if (an == "turnpause") {				jumpWait = Math.abs(Number(vn));			} else if (an == "frontpause") {				frontPause = Math.abs(Number(vn));			} else if (an == "gotopage") {				setGotoStyle(vn.toLowerCase());			} else if (an == "flipspeed") {				setFlippingStyle(vn.toLowerCase());			} else if ((an == "headersize") || (an == "pagenumbersize")) {				vn = replaceString (vn.toLowerCase(), "pt", "");//remove point				vn = replaceString (vn, "px", "");//remove pixels				vn = replaceString (vn, " ", "");//remove the space				var isAdd = 0;				//we need to change the relative font size to fixed one				if (vn.indexOf("+") == 0) {					vn = replaceString(vn, "+", "");					isAdd = 1;				} else if (vn.indexOf("-") == 0) {					vn = replaceString(vn, "-", "");					isAdd = -1;				}				var font_size = Number(vn);				if (isNaN(font_size) == true) {					font_size = 0;				} else if (isAdd != 0) {					var fSize = 12;					//the current line of the book					var currLine = currParagraph[currParagraph.length - 1];					if (currLine != null)						fSize = currLine.fontSize;					font_size = fSize + (isAdd * font_size); 				}				font_size = Math.min(Math.max(1, font_size), 									 test_content._width - 30);								if (an == "headersize")					headerSize = font_size;				else					numberSize = font_size;			}  		}	}}/** * Parse the section tag * Parameters: * currNode current XML node we want to parse * section the current book section we are building * Return * the section once the end section tag is encountered  */function parseSectionTag (currNode, section) {	var currName = (currNode.nodeName).toLowerCase();	completeCurrParagraph();		var csec = section;	if (currName.charAt(0) == "h") {		s_level = Number(currName.substr(1));		while ((csec != null) && (csec.section_level >= s_level)) {			csec = csec.section_parent;		}	}	var s_level = csec.section_level + 1;//increment the section level	var s_tnum = setSectionNumber(csec); 		if (headerStyle[s_level] == null) {		initHeaderStyle(s_level);	}		img_counter = 0;//reset the image counter	var isSecNewPage = headerStyle[s_level].pagebreak;		var b_page = pages[pages.length - 1];	var new_section = new BookSection(s_tnum, "", s_level);	csec.subsection.push(new_section);		//get all the possible attribute values of the section tag	new_section.section_level = s_level;	var map = getAttrMapFor (currNode);	new_section.section_align = getAttrValue(map, "align", 											 headerStyle[s_level].align);	new_section.section_addtitle = getAttrValue(map, "addtitle", true);	new_section.section_bold = getAttrValue(map, "bold", 											 headerStyle[s_level].bold);	new_section.section_font = getAttrValue(map, "face", 											 headerStyle[s_level].face);	new_section.section_italic = getAttrValue(map, "italic", 											 headerStyle[s_level].italic);	new_section.section_fsize = getAttrValue(map, "size", 											 headerStyle[s_level].size);	isSecNewPage = getAttrValue(map, "pagebreak", isSecNewPage);	var slide_filenames = getAttrValue(map, "filename", new Array());	if (slide_filenames.length > 0)		isSecNewPage = true;	new_section.section_newpage = isSecNewPage;		var b_page = pages[pages.length - 1];	var nPage = null;	if (isSecNewPage == true) {		if ((b_page.page_slidesname.length == 0) && 			(_root.strIsEmpty(b_page.page_text) == false)) {			var pStr = "";			if (isEndTagABlock() == true) {				pStr += end_style.substring(end_inline.length);			} else {				pStr += end_style;			}			b_page.page_text += pStr;			addNewline(b_page, end_style);			updateHTMLIndex (b_page);		}					if ((_root.strIsEmpty(b_page.plain_text) == false) || 			((pages.length % 2) == 1)) {			isImg = 0;			var new_page = new BookPage(pages.length, "", new_section);			pages.push(new_page);			new_section.section_page = new_page;			nPage = new_page;		} else {			new_section.section_page = b_page;			b_page.page_section = [new_section];			nPage = b_page;		}		//if the start of the section is not on the right side add a new page		if ((pages.length % 2) == 1) {			isImg = 0;			new_page.page_section = [getLastSection(b_page)];			var new_page2 = new BookPage(pages.length,"", new_section);			pages.push(new_page2);			//set it to be the section starting page			new_section.section_page = new_page2;			nPage = new_page2;		}				if (slide_filenames.length > 0) {			nPage.page_slidesname = slide_filenames;			nPage.totalframes = nPage.page_slidesname.length;		}	} else {		b_page.page_section.push(new_section);//section this page belongs to		new_section.section_page = b_page;	}		if (currName == "section") {//keep recurse down the tree		var passSection = parseTree(currNode, new_section);		if (passSection.section_level != new_section.section_level) {			//there's a header tag inside the section tag			return passSection;		}		return section;	} else {		var vn = currNode.childNodes[0].nodeValue;		var s_title = convertHTMLEntities(vn);		new_section.section_title = s_title;		writeSectionTitle (new_section);		return new_section;	}}/** * Recursively goes down the XML node and build the book.  * Parameters: * currNode	current XML node we want to parse * section	the current book section we are building */function parseTreeXMLNode (currNode, section) {	//the tag name	var currName = (currNode.nodeName).toLowerCase();	//the current line of the book	var currLine = currParagraph[currParagraph.length - 1];	if ((currName == "bookmarklist") || (currName == "annotationlist")) {		var attr = currNode.attributes;		for (var attr_name in attr) {			if (attr_name.toLowerCase() == "pagenum") {				var val = attr[attr_name];				if ((_root.strIsEmpty(val) == false) && (isNaN(val) == false)) {					parseBookmarkAnnotation(currNode, Number(val));				}			}		}	} else if ((currName == "section") || (currName.charAt(0) == "h")) {		return parseSectionTag(currNode, section);	} else if (currName == "description") {		parseDescriptionTag(currNode, section);	} else if (currName == "newpage") {		completeCurrParagraph();		var map = getAttrMapFor (currNode);		var slide_filenames = getAttrValue(map, "filename", new Array());		var b_page = pages[pages.length - 1];		if ((b_page.page_slidesname.length == 0) && 			(_root.strIsEmpty(b_page.page_text) == false)) {			b_page.page_text += end_style;			updateHTMLIndex (b_page);			addNewline(b_page, end_style);		}		isImg = 0;		var new_page = new BookPage(pages.length, "", section);		pages.push(new_page);		if (slide_filenames.length > 0) {			new_page.page_slidesname = slide_filenames;			new_page.totalframes = slide_filenames.length;		}	}		return section;}/** * Given the text node, write the text to the page * Parameters: * currNode the text node */function parseTextTag (currNode) {	//the current line of the book	var currLine = currParagraph[currParagraph.length - 1];		var s_text = currNode.nodeValue;//get the node value inside the HTML tag		s_text = replaceString (s_text, "\n", " ");//remove all the newline	s_text = replaceString (s_text, "\r", " ");//remove all the newline	while (s_text.indexOf("  ") != -1) {		s_text = replaceString (s_text, "  ", " ");//remove all extra space	}	s_text = convertHTMLEntities(s_text);//convert the HTML entities		if (currLine == null) {		currLine = addALineToCurrParagraph();	}		if (s_text.charAt(0) == ' ') {//remove additional space		if ((currLine.plain_text.length == 0) || 			(currLine.plain_text.charAt(currLine.plain_text.length - 1) == ' ')) {			s_text = s_text.substring(1, s_text.length);		}	}		var s_word = 0;	test_content.htmlText = currLine.lineStartStyle + currLine.lineText + "W";	var tf = test_content.getTextFormat(0, test_content.text.length);	currLine.lineLeading = tf.leading;	var charWidth = test_content.textWidth - currLine.lineWidth;	var maxWidth = Math.floor(test_content._width - (3 * currLine.fontSize));	//do the line breaking	while (s_text.length > 0) {		if (((s_text.length * charWidth) + currLine.lineWidth) <= maxWidth) {			currLine = writeToLine (currLine, s_text);			s_text = "";		} else {			var estChar = Math.floor((maxWidth - currLine.lineWidth)/charWidth);			if (estChar == 0) {				estChar = Math.floor(maxWidth/charWidth);			}			estChar = Math.min(estChar, s_text.length);			var wI = estChar;			if (estChar < s_text.length) {				//get the last word				var spaceIndex = s_text.lastIndexOf(" ", estChar);				wI = spaceIndex;				if (spaceIndex == -1) {					wI = estChar;					var spaceIndex2 = s_text.indexOf(" ", estChar);					if (spaceIndex2 == -1)						spaceIndex2 = s_text.length  - 1;										var w2_text = s_text.substring(0, spaceIndex2 + 1);					test_content.htmlText = currLine.lineStartStyle + 											currLine.lineText + w2_text;					if ((test_content.textWidth - currLine.lineWidth) <= maxWidth) {						wI = spaceIndex2;					}				}			}			var w_text = s_text.substring(0, wI + 1);			currLine = writeToLine (currLine, w_text);			s_text = s_text.substr(wI + 1);		}	}}/** * Write the current line tag, given the starting tag and ending tag * Parameters: * sTag start tag * eTag end tag */function writeStartTagToText (sTag, eTag) {	start_style = start_style + sTag;	end_style = eTag + end_style;	//the current line of the book	var currLine = currParagraph[currParagraph.length - 1];		currLine.lineText += sTag;	currLine.lineEndStyle = eTag + currLine.lineEndStyle;	test_content.htmlText = currLine.lineStartStyle + currLine.lineText;	currLine.lineWidth = test_content.textWidth;	currLine.lineHeight = test_content.textHeight;	var tf = test_content.getTextFormat(0, test_content.text.length);	if (tf.leading == null) {		var b_page = pages[pages.length - 1];		test_content.htmlText = b_page.page_text;		tf = test_content.getTextFormat(test_content.text.length - 1, 										test_content.text.length);		if (tf.leading == null)			tf.leading = 0;	}	currLine.lineLeading = tf.leading;}/** * Write the closing tag to text * Parameters: * eTag 			end tag * old_end_style	the previous end style */function writeCloseTagToText (eTag, old_end_style) {	if (currParagraph.length == 0) {//we have written all the text		//the end tag should just be appended to the last page		var b_page = pages[pages.length - 1];		b_page.page_text += eTag;	} else {		//the current line of the book		var currLine = currParagraph[currParagraph.length - 1];		currLine.lineText += eTag;		currLine.lineEndStyle = old_end_style;		test_content.htmlText = currLine.lineStartStyle + currLine.lineText;		currLine.lineWidth = test_content.textWidth;		currLine.lineHeight = test_content.textHeight;		var tf = test_content.getTextFormat(0, test_content.text.length);		currLine.lineLeading = tf.leading;	}	}/** * See whether the end of the last line is a block tag. */function isEndTagABlock () {	var b_page = pages[pages.length - 1];	var txt = b_page.page_text;	if (currParagraph.length > 0) {		var currLine = currParagraph[currParagraph.length - 1];		if (_root.strIsEmpty(currLine.lineText) == false) {			txt = currLine.lineText;		}	}		var bTag = ["</p>","</soc>","</li>"];	var eID = -1;	for (var i = 0; i < bTag.length; i++) {		var id = txt.lastIndexOf(bTag[i]);		if (id != -1) {			if (id == (txt.length - bTag[i].length)) {				return true;			} else {				eID = Math.max(eID, id + bTag[i].length);			}		}	}		if (eID == -1) {		return false;	}		var rem = txt.substring(eID);	while (rem.length > 0) {		var bid = rem.indexOf("<");		if (bid != -1) {			var fid = rem.indexOf(">", bid);			if (rem.lastIndexOf("/", fid) != -1) {				if ((fid + 1) == rem.length) {					return true;				} else {					rem = rem.substring(fid + 1);				}			} else {				var tid = Math.min(fid, rem.indexOf(" ",bid));				var tName = rem.substring(bid + 1, tid);				var eTag = "</" + tName + ">";				var sid = rem.indexOf(eTag, fid + 1);				if (sid != -1) {					if ((sid + eTag.length) == rem.length) {						return true;					} else {						rem = rem.substring(sid + eTag.length);					}				} else {					return false;				}			}		} else {			return false;		}	}		return false;}/** * Set the start and end style to contain only the block tag */function setOnlyBlockStyle () {	start_style = start_style.substring(0, start_style.length - start_inline.length);	end_style = end_style.substring(end_inline.length);}/** * Update the last html line index of the specified page * Parameters: * b_page the page */function updateHTMLIndex (b_page) {	if ((b_page != null) && (b_page.page_line.length > 0)) {		var lm = b_page.page_line[b_page.page_line.length - 1];		lm.htmlLineIndex = b_page.page_text.length;	}}/** * Parse all the paragraph tag (img, p, br, li, soc) * Parameters: * currNode the current node * section	the current section */function parseParagraphTag (currNode, section) {	var currName = (currNode.nodeName).toLowerCase();//the tag name	//get the attributes of each tag	var map = getAttrMapFor (currNode);	var s_attr = map["map_text"];//write the attributes in a string					var old_start_style = start_style;	var old_end_style = end_style;	var old_text_align = text_align;	var old_start_inline = start_inline;	var old_end_inline = end_inline;		if (currName == "p") {		var pAlign = getAttrValue(map, "align", "left");		text_align = pAlign;		s_attr = " align='" + pAlign + "'";	}		if ((currName == "p") || (currName == "soc") || (currName == "li")) {		setOnlyBlockStyle ();		if (isEndTagABlock() == false)			writeCloseTagToText (end_inline, end_style);	}	var act_old_end = end_style;	var act_old_start = start_style;		writeParagraphToPage();//we need to write all the lines before this tag		//the current line of the book	var currLine = currParagraph[currParagraph.length - 1];		if (currParagraph.length == 0)		currLine = addALineToCurrParagraph();//create a new line		if (currName == "img") {		var img_name = getAttrValue(map, "src", "");//image url		var img_width = getAttrValue(map, "width", 0);//image width		var img_height = getAttrValue(map, "height", 0);//image height				//add the modified image tag to the section's content		var img_text = setImageSize(img_name,img_width,img_height);		img_counter++;//increment the image counter for this section		var img_title = "Figure " + section.section_tnum + "." + img_counter;		var bimg = new BookImage(img_title);//create a BookImage object 		test_content.htmlText = img_text;		var w_height = test_content.textHeight;		var w_width = test_content.textWidth;						var tf = test_content.getTextFormat(0, test_content.text.length);		currLine.lineLeading = tf.leading;		currLine.lineText += img_text;		currLine.plain_text += test_content.text;		currLine.lineWidth = w_width;		currLine.lineHeight = Math.max(currLine.lineHeight, w_height);		currLine.lineImage = bimg;		var lastLink = currLine.lineLinks[currLine.lineLinks.length - 1];		if (lastLink != null) {			lastLink.linkWidth = w_width;			lastLink.linkHeight = currLine.lineHeight;		}	} else {		var sTag = "<" + currName + s_attr +">";		var eTag = "</" + currName + ">";				if ((currName == "p") || (currName == "soc") || (currName == "li")) {			sTag += start_inline;			eTag = end_inline + eTag;		} else {			eTag = eTag;		}				writeStartTagToText (sTag, eTag);		section = parseTree(currNode, section);		if (isEndTagABlock() == true) {			eTag = "</" + currName + ">";		} else {			eTag = eTag;		}		writeCloseTagToText (eTag, act_old_end);	}		if ((currName != "img") && (currName != "soc")) {		if (currParagraph.length == 0) {			b_page.plain_text += "\r";		} else {			currLine.plain_text += "\r";		}	}		start_style = act_old_start;	end_style = act_old_end;	//we need to write all the lines in this tag	writeParagraphToPage();		start_style = old_start_style;	end_style = old_end_style;	text_align = old_text_align;	start_inline = old_start_inline;	end_inline = old_end_inline;		return section;} /** * Parse all the inline tag (font, i, b, a, u, textformat, span) * Parameters: * currNode the current node * section  the current section */function parseInlineTag (currNode, section) {	var currName = (currNode.nodeName).toLowerCase();//the tag name	//get the attributes of each tag	var map = getAttrMapFor (currNode);	var s_attr = map["map_text"];//write the attributes in a string			var font_size = 12;//the font size	if (currLine != null)		font_size = currLine.fontSize;		var old_start_style = start_style;	var old_end_style = end_style;	var old_text_align = text_align;	var old_start_inline = start_inline;	var old_end_inline = end_inline;		var isEnd = isEndTagABlock();	if (isEnd == true) {		setOnlyBlockStyle ();	}	var act_old_end = end_style;		//the current line of the book	var currLine = currParagraph[currParagraph.length - 1];		if (currParagraph.length == 0)		currLine = addALineToCurrParagraph();//create a new line			var sTag = "<" + currName + s_attr +">";	var eTag = "</" + currName + ">";		var old_font = currLine.fontSize;	if (currName == "font") {		font_size = getAttrValue(map, "size", font_size);//the font size		currLine.fontSize = font_size;			} else if (currName == "a") {		var linkURL = getAttrValue(map, "href", "");//link destination		var linkStatus = getAttrValue(map, "active", true);//link active status		var linkSynonym = getAttrValue(map, "synonym", false);//find synonym		var linkName = getAttrValue(map, "name", "");//internal link name		var overText = getAttrValue(map, "title", "");//mouse over text		if (_root.strIsEmpty(linkURL) == true) {			linkStatus = false;		}		if ((_root.strIsEmpty(overText) == false) ||			(_root.strIsEmpty(linkName) == false) ||			(linkSynonym == true)) {			isLink = true;			var bl = new BookLink();			bl.linkText = overText;			bl.linkName = linkName;			bl.linkX = currLine.lineWidth;			bl.linkURL = linkURL;			currLine.lineLinks.push(bl);									if ((overText.indexOf("wikiid:") == 0) && 				(map["synonym"] == null)) {				wikiID = overText; 				if (wikiList[wikiID] == null) {					wikiList[wikiID] = [];					if (_root.strIsEmpty(linkURL) == false) {						var wa = "www.wikipedia.org/";						var wi = linkURL.indexOf(wa);						if (wi != -1) {							var wtitle = linkURL.substr(wi + wa.length);							wtitle = replaceString(wtitle, "/", "");							wtitle = replaceString(wtitle, "_", " ");							wikiList[wikiID].push(wtitle);						}					}				}				if (linkSynonym == false) {					sTag = replaceString(sTag,'<a ', 										 '<a synonym="true" ');				}			} else if (linkSynonym == true) {				wikiID = linkURL;				if (wikiList[wikiID] == null) {					wikiList[wikiID] = [];				}			}		}				if (linkStatus == true) {			if (map["active"] == null) {				sTag.replaceString(sTag, '<a ', '<a active="true" ');			}						sTag = "<font color='#0000FF'>" + sTag;			eTag += "</font>";		}	}		start_inline += sTag;	end_inline = eTag + end_inline;		if (isEnd == true) {		sTag = start_inline;		eTag = end_inline;	}			writeStartTagToText (sTag, eTag);	section = parseTree(currNode, section);		if (isEndTagABlock() == false)		writeCloseTagToText (eTag, act_old_end);		if (currName == "font") {		currLine.fontSize = old_font;	} else if (currName == "a") {		isLink = false;						wikiWord = wikiWord.toLowerCase();		if ((strIsEmpty(wikiWord) == false) && (wikiList[wikiWord] == null)) {			wikiList[wikiWord] = wikiID;			wikiList[wikiID].push(wikiWord);		}		wikiWord = "";		wikiID = "";	}		start_style = old_start_style;	end_style = old_end_style;	text_align = old_text_align;	start_inline = old_start_inline;	end_inline = old_end_inline;		return section;}/** * Recursively goes down the HTML node and build the book.  * Parameters: * node	current HTML node we want to parse * section	the current book section we are building */function parseTreeHTMLNode (currNode, section) {	var currName = (currNode.nodeName).toLowerCase();//the tag name	var s_attr = "";//write the attributes in a string 	if ((currName == "style") || (currName == "script") || 		(currName == "link") || (currName == "meta")) {		//do nothing if it is under the ignored tag	} else if ((currName == "title") && (isSetTitle == false)) {		var s_title = currNode.childNodes[0].nodeValue;		ExternalInterface.call("setDocumentTitle", s_title);		isSetTitle = true;	} else if ((currName == "head") || (currName == "body") || 			   (currName == "html")) {		//keep recurse down the tree		section = parseTree(currNode, section);	} else {		if (currName == null) {//it's a text tag			parseTextTag (currNode);		} else if ((currName == "img") || (currName == "p") || 				(currName == "br") || (currName == "li") || 				(currName == "soc")) {//it's a paragraph tag			section = parseParagraphTag (currNode, section);		} else if ((currName == "u") || (currName == "a") || 				   (currName == "b") || (currName == "font") || 				   (currName == "i") || (currName == "span") || 				   (currName == "textformat")) {			section = parseInlineTag (currNode, section);		} else { //unrecognized html tag			//keep recurse down the tree			section = parseTree(currNode, section);		}	}		return section;}/** * Add newline character into the page object plain text given the end tag */function addNewline(b_page, endTagList) {	if (strIsEmpty(endTagList) == true)		return;			var endName = ["</p>", "</br>", "</li>"];	for (var ei = 0; ei < endName.length; ei++) {		var si = endTagList.indexOf(endName[ei]);		while (si != -1) {			b_page.plain_text += "\r";			si = endTagList.indexOf(endName[ei],si + endName[ei].length);		}	}}/** * Write each lines inside the paragraph to the book pages. */function writeParagraphToPage () {	if (currParagraph.length == 0) {		return;	}	if (currParagraph.length == 0) {		return;	}	var b_page = pages[pages.length - 1];	var b_section = getLastSection(b_page);	var lastLine = currParagraph[currParagraph.length - 1];	text_height += lastLine.lineHeight;	if (currParagraph.length <= orphanLine)		orphan_height += lastLine.lineHeight;			var endTagList = end_style;	var esi = end_style.indexOf(">");	if (currParagraph[0].lineStartStyle != start_style) {		var e_style = "";		var s_style = currParagraph[0].lineStartStyle;		while (s_style.length > 0) {			var psid = s_style.indexOf(">");			var spid = Math.min(psid, s_style.indexOf(" "));			var tnid = s_style.substring(1, spid);			e_style = "</" + tnid + ">" + e_style;			s_style = s_style.substring(psid + 1);		}				endTagList = e_style;	}		test_content.htmlText = b_page.page_text;	var accHeight = test_content.textHeight;	updateHTMLIndex (b_page);		var tstOrphan = false;//whether we should check the orphan &  widow constraints	if ((b_page.page_slidesname.length > 0) || 		((text_height + test_content.textHeight + yAdd) >= test_content._height)) {		//we cannot write all the lines into this page, 		//so we need to check it against our orphan and widow constraints		tstOrphan = true;				if ((b_page.page_slidesname.length > 0) ||			((orphan_height + test_content.textHeight + yAdd) >= test_content._height) ||			((currParagraph.length - orphanLine) < widowLine)) {			//we need to write it into a new page			if (test_content.textHeight > 0) {				if ((b_page.page_slidesname.length == 0) && 					(_root.strIsEmpty(b_page.page_text) == false)) {					b_page.page_text += endTagList;					updateHTMLIndex (b_page);					addNewline(b_page, endTagList);				}				var firstLine = currParagraph[0];				isImg = 0;				var new_page = new BookPage(pages.length,											firstLine.lineStartStyle,b_section);				pages.push(new_page);				b_page = new_page;				test_content.htmlText = firstLine.lineStartStyle;				accHeight = test_content.textHeight;				tstOrphan = false;			}		}	} else {		if (strIsEmpty(b_page.page_text) == true) {			var firstLine = currParagraph[0];			b_page.page_text = firstLine.lineStartStyle;			test_content.htmlText = firstLine.lineStartStyle;			accHeight = test_content.textHeight;		}	}		var header_margin = 0;	if (addRunningHeader == true)		header_margin = 2 * (headerSize + 6);		var lOffY = 0 - Math.ceil(test_content._parent.bg._height)/2 + top_margin + header_margin;	var lOffX = 0 - test_content._parent.bg._width/2 + left_margin;	//var lOffY = 0 - Math.ceil(test_content._height/2);	//var lOffX = 0 - Math.ceil(test_content._width/2);	for (var i = 0; i < currParagraph.length; i++) {		var currLine = currParagraph[i];		test_content.htmlText = b_page.page_text + currLine.lineText;		if ((test_content.textWidth > 0) && 			(accHeight == test_content.textHeight) && 			(i == 0) && (currLine.lineWidth > 0)) {			//we need to add additional break because in flash 			//if the syntax is not correct it won't add the page break			b_page.page_text += "<toc><br /></toc>";			b_page.plain_text += "\r";			test_content.htmlText = b_page.page_text + currLine.lineText;		}				var isNewPage = false;		if ((tstOrphan == true) && (i >= orphanLine) && 			((currParagraph.length - i - 1) < widowLine)) {			//even when the line fit on the current page			//the line should be in the next page to meet the widow constrains			isNewPage = true;		}			if ((isNewPage == false) && 			((test_content.textHeight + yAdd) < test_content._height)) {			b_page.page_text += currLine.lineText;			b_page.plain_text += currLine.plain_text;		} else {			test_content.htmlText = b_page.page_text;			if (test_content.textHeight > 0) {				if (i > 0) { 					endTagList = currParagraph[i-1].lineEndStyle;				}								if (_root.strIsEmpty(b_page.page_text) == false) {					addNewline(b_page, endTagList)					b_page.page_text += endTagList;					updateHTMLIndex (b_page);				}								isImg = 0;				var new_page = new BookPage(pages.length,											currLine.lineStartStyle,b_section);				pages.push(new_page);				b_page = new_page;				accHeight = 0;				tstOrphan = false;			}			b_page.page_text += currLine.lineText;			b_page.plain_text += currLine.plain_text;		}				test_content.htmlText = b_page.page_text;		var tlHeight = test_content.textHeight - accHeight;		if ((tlHeight != currLine.lineHeight) && 			(currLine.lineText != "<br /></br>")) {//fix the line height			if ((currLine.lineLeading != 0) && 				(Math.abs(currLine.lineHeight - currLine.lineLeading) == tlHeight)) {				currLine.lineLeading = 0;				b_page.page_line[b_page.page_line.length - 1].lineLeading *= -1;			}			currLine.lineHeight = tlHeight;		}		if ((isImg == 0) && (currLine.lineText.indexOf("<img") > -1)) {			isImg -= line_height;		}				//store the LineMetric information		if (currLine.plain_text.length > 0) {			var lIndex = currLine.plain_text.length;			if (b_page.page_line.length > 0) {				lIndex += b_page.page_line[b_page.page_line.length - 1].lineIndex;			}			var lHeight = currLine.lineHeight;			var lY = lOffY + accHeight + 2;			var lWidth = currLine.lineWidth + 4;			var origX = 2;			if (currLine.lineAlign == "center") {				origX = (test_content._width - currLine.lineWidth)/2;			} else if (currLine.lineAlign == "right") {				origX = test_content._width - currLine.lineWidth - 2;			}			var lX = Math.ceil(origX);			var lm = new LineMetric(lIndex, lX, lY + isImg, lWidth, lHeight, 									currLine.lineLeading);			lm.htmlLineIndex = b_page.page_text.length;			b_page.page_line.push(lm);		}				//store the links and its information to the  page		for (var li = 0; li < currLine.lineLinks.length; li++) {			var bl = currLine.lineLinks[li];			if (_root.strIsEmpty(bl.linkName) == false) {				page_link[bl.linkName] = b_page;			} else if (_root.strIsEmpty(bl.linkText) == false){				bl.linkHeight = lHeight;				bl.linkY = lY;				bl.linkWidth += 4;				bl.linkX = lX + Math.ceil(lOffX + bl.linkX);				b_page.page_link.push(bl);			}		}				//store the images to the page		if (currLine.lineImage != null) {			b_page.page_image.push(currLine.lineImage);		}				accHeight += currLine.lineHeight;	}		updateHTMLIndex (b_page);	currParagraph = new Array();	text_height = 0;	orphan_height = 0;}/** * Write the current word to the specified line * Parameters: * currLine	the current book line * w_text	the word to be written to the line */function writeToLine (currLine, w_text) { 	if (w_text.length == 0) 		return currLine;			test_content.htmlText = currLine.lineStartStyle + currLine.lineText + 							w_text + currLine.lineEndStyle;	var w_width = test_content.textWidth;//the current line width	var w_height = test_content.textHeight;	var lw_width = w_width;	w_width = w_width - currLine.lineWidth;//the word width	if (w_width == 0)		return currLine;		if (lw_width >= Math.floor(test_content._width - (3 * currLine.fontSize))) {		//cannot fit into the same line		//create a new line		if (currLine.lineText.charAt(currLine.lineText.length - 1) == ' ') {			currLine.lineText = currLine.lineText.substr(0,														 currLine.lineText.length - 1);		} else {			currLine.plain_text += ' ';		}		currLine.lineText += '<toc><br /></toc>';		text_height += currLine.lineHeight;		if (currParagraph.length <= orphanLine) {			orphan_height += currLine.lineHeight;		}		var newLine = new BookLine();		newLine.fontSize = currLine.fontSize;		newLine.lineLeading = currLine.lineLeading;		newLine.lineStartStyle = start_style;		newLine.lineEndStyle = end_style;		newLine.lineAlign = text_align;		if (isLink == true) {//this text belongs to a hyperlink with mouse over			var lastLink = currLine.lineLinks[currLine.lineLinks.length - 1];			var newLink = new BookLink();			newLink.linkText = lastLink.linkText;			newLink.linkURL = lastLink.linkURL;			newLine.lineLinks.push(newLink);			if (lastLink.linkWidth == 0) {				//there is no text inside the link so we should delete it				currLine.lineLinks.pop();				delete lastLink;			}		}		currParagraph.push(newLine);		currLine = newLine;				if (w_text.charAt(0) == ' ') {			w_text = w_text.substring(1, w_text.length);		}	}	currLine.lineText += w_text;	currLine.plain_text += w_text;	currLine.lineWidth += w_width;	currLine.lineHeight = w_height;	if (isLink == true) {		var lastLink = currLine.lineLinks[currLine.lineLinks.length - 1];		lastLink.linkWidth += w_width;		lastLink.linkHeight = currLine.lineHeight;		if (wikiID != "")			wikiWord += w_text;	}	return currLine;}/** * Rescale the image to fit the page * Parameters: * img_name	the image's source file URL  * img_width	image's width * img_height	image's height */function setImageSize(img_name,img_width,img_height) {	var hspace = 10;//the horizontal pad	var vspace = 10;//the vertical pad	var scale_width = 1;//the x scaling factor	var scale_height = 1;//the y scaling factor	if (img_width >= test_content._width)	{//image is wider than the page so x scale		var new_img_width = test_content._width - (2 * hspace);		scale_width = new_img_width/img_width;	}	else	{		//figure has to be centered means we need to pad the space		hspace = (test_content._width - img_width)/2;	}					if (img_height >= test_content._height)	{//image is taller than the page so y scale		var new_img_height = test_content._height - (2 * vspace);		scale_height = new_img_height/img_height;	}		//scale image with the smallest factor	var scale = Math.min(scale_width,scale_height);	img_width = img_width * scale;	img_height = img_height * scale;		var break_text = "";//put break according to the size of the image	//the current line of the book	var currLine = currParagraph[currParagraph.length - 1];	var num =  (img_height + (2 * vspace))/(currLine.lineLeading + line_height);	isImg -= line_height;	for (var t = 0; t < num; t++)		break_text += "<br />";		var img_txt = "<toc><br /></toc><img src ='" + img_name + 				  "' width ='" + img_width + "' height ='" + img_height + 				  "' hspace ='" + hspace + "' vspace ='" + vspace + 				  "' align ='left' /><toc>" + break_text + "</toc>";	return img_txt;}/*----------- Create table of content ------------*//** * Create the table of content automatically * Parameters: * section	a section of the book * pages2	array of pages in the book */function createTableOfContent(section,pages2) {	for (var i = 0; i < section.subsection.length; i++) {		//if the section is belongs to the book's content not the cover		if ((_root.strIsEmpty(section.subsection[i].section_tnum) == false) || 			(i > 0)) {				//set the text information of the section and 			//hyperlink to go to the section			var link = "<a href='asfunction:_root.gotoPage," + 					   section.subsection[i].section_page.page_num + "'>";			var tabs = "<textformat indent='"+ 					   (section.subsection[i].section_level * 10) + "'>";			var txt = "";			if (section.subsection[i].section_level <= 2) {				txt += "<br />";			}			txt += "<p align='left'><font color='#0000FF'>" + tabs + 					section.subsection[i].section_tnum;			if (strIsEmpty(section.subsection[i].section_tnum) == false)				txt += " ";			txt += link + section.subsection[i].section_title; 			txt += "</a> <i>" + 				   getPage_Number(section.subsection[i].section_page.page_num) + 				   "</i></textformat></font></p>";					test_content.htmlText = txt;			var ptxt = test_content.text;						//add it to the existing text in the page			var b_page = pages2[pages2.length - 1];			var curr_page_text = b_page.page_text;			test_content.htmlText = (curr_page_text + txt);						//if it is bigger than one page,create a new page			if ((test_content.textHeight + yAdd) < test_content._height) {				b_page.page_text += txt;				b_page.plain_text += ptxt;			} else {				updateHTMLIndex (b_page);				var new_page = new BookPage(pages2.length,"<wrap />" + 											txt,books[0].subsection[0]);				new_page.plain_text = ptxt;				pages2.push(new_page);			}		}		//recursively go to the next section		createTableOfContent(section.subsection[i],pages2);	}}/** * Fix the page numbering and set the bookmark position in each page of the book. */function fixPageNumber() {	var b_numS = 0;//bookmark_number based on section	var b_numP = 0;//bookmark_number based on picture	for (var i = 0; i < pages.length; i++) {		//setting the start_numbering variable		if (start_numbering == -1) {			for (var pp = 0; pp < pages[i].page_section.length; pp++) {				if (Number(pages[i].page_section[pp].section_tnum) == 1) {					start_numbering = i;					break;				}			}		}				pages[i].page_num = i;//set the page number		/*trace(i);		for (var li = 0; li < pages[i].page_line.length; li++) {			var lm = pages[i].page_line[li];			if (lm != null) {				//lm.toText();				var spi = 0; var epi = pages[i].page_line[li].lineIndex;				var shi = 0; var ehi = pages[i].page_line[li].htmlLineIndex;				if (li > 0) {					spi = pages[i].page_line[li - 1].lineIndex;					shi = pages[i].page_line[li - 1].htmlLineIndex;				}				trace('line:' + li);				trace('text:' + pages[i].plain_text.substring(spi, epi));				trace('htmltext:' + pages[i].page_text.substring(shi, ehi));			}		}*/				if ((pages[i].page_section.length > 1) || 			(pages[i].page_section[0].section_page.page_num == i)) {			//setting the y position of the bookmark based on section			addBookmarkToPage ("S", b_numS % bookmark_cutoff, 							   pages[i].page_bookmarktext, i);			pages[i].page_bookmarktext = "";			b_numS++;		}				if (pages[i].page_image.length > 0) {			//setting the y position of the bookmark based on image			addBookmarkToPage ("P", b_numP % bookmark_cutoff, "", i);			b_numP++;		}	}}